<?php

DEFINE( 'SESSION_DB', 1 );
DEFINE( 'SESSION_PHP', 2 );

/*
 * session_handler_init()
 */
function session_handler_init() {
	global $config;

	$handler = isset($config['session']['handler']) ? $config['session']['handler'] : SessionHandlerType::PHP;
	SessionHandlerFactory::Create($handler);
}

class Session {

	public static function GetValue() {
		
	}
}

class SessionHandlerType {
	const DB = 1;
	const PHP = 2;
	const MEM = 3;
}

class SessionHandlerFactory {

	public static function Create($type_or_class = SessionHandlerType::PHP, array $params = array()) {
		switch ($type_or_class) {
			case SessionHandlerType::DB:
				$class = 'SessionHandlerDB';
				break;
			case SessionHandlerType::PHP:
				$class = null;
				break;
			case SessionHandlerType::MEM:
				$class = 'SessionHandlerMEM';
				break;
			default:
				$class = is_string($type_or_class) ? $type_or_class : null;
				break;
		}

		if (!is_null($class) && is_subclass_of($class, 'SessionHandlerBase')) {
			return new $class($params);
		} else {
			session_start();
			return null;
		}
	}
}

abstract class SessionHandlerBase {
	protected $_path;
	protected $_name;

	public function __construct() {
		session_set_save_handler(
			array($this, 'Open'),
			array($this, 'Close'),
			array($this, 'Read'),
			array($this, 'Write'),
			array($this, 'Destroy'),
			array($this, 'GC')
		);

		session_start();
	}

	public abstract function Open($save_path, $session_name);
	public abstract function Close();
	public abstract function Read($id);
	public abstract function Write($id, $sess_data);
	public abstract function Destroy($id);
	public abstract function GC($maxlifetime);
}

final class SessionHandlerDB extends SessionHandlerBase {
	private $_table;
	private $_schema;
	private $_session;

	public function __construct(array $params) {
		$this->_table = isset($params['table']) ? $params['table'] : 'php_sess';
		$this->_schema = isset($params['schema']) ? $params['schema'] :
			array(
				'id'   => 'sess_id',
				'time' => 'time',
				'name' => 'name',
				'data' => 'data'
			);

		parent::__construct();
	}

	/*
	 * Open()
	 */
	public function Open($save_path, $session_name) {
		$this->_name = $session_name;

		$session = DB::Table( $this->_table )->Where( $this->_schema[ 'id' ], EQ, session_id() );

		if ($session->Exists()) {
			$session = $session->Columns(array_values($this->_schema))
								->OrderBy($this->_schema['time'], DESC)
								->Single();
		} else {
			$session = DB::Table($this->_table)->NewObject();

			if (is_string($session->PrimaryKey)) {
				session_id($session->PrimaryKey);
			} else {
				$session->SetValue($this->_schema['id'], session_id());
			}
		}

		$session
			->SetValue($this->_schema['name'], $session_name)
			->SetValue($this->_schema['time'], time());

		$this->_session = $session;

		return true;
	}

	/*
	 * Close();
	 */
	public function Close() {
		return true;
	}

	/*
	 * Read()
	 */
	public function Read($id) {
		return DB::IfNull($this->_session->GetValue($this->_schema['data']), false);
	}

	/*
	 * Write()
	 */
	public function Write($id, $sess_data) {
		return $this->_session->SetValue($this->_schema['data'], $sess_data)->Save();
	}

	/*
	 * Destroy()
	 */
	public function Destroy($id) {
		return DB::Table($this->_table)->Where($this->_schema['id'], EQ, $id)->Delete();
	}

	/*
	 * GC()
	 */
	function GC($maxlifetime) {
		return DB::Table($this->_table)->Where($this->_schema['time'], LT, DBDateTime::Parse(time() - $maxlifetime))->Delete();
	}

}
